home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / MacPNG Library 1.02 / pngMacSrc 1.02 / png.1 / pngcheck.c < prev    next >
C/C++ Source or Header  |  1995-08-24  |  9KB  |  350 lines

  1. /*
  2.  * authenticate a PNG file (as per draft 10)
  3.  *
  4.  * this program checks the PNG identifier with conversion checks,
  5.  * the file structure and the chunk CRCs.
  6.  *
  7.  * With -v switch, the chunk names are printed.
  8.  * with -t switch, text chunks are printed (without any charset conversion,
  9.  *                                          works on X11R>=5 OK)
  10.  *
  11.  * written by Alexander Lehmann <alex@hal.rhein-main.de>
  12.  *
  13.  *
  14.  * 23.02.95 fixed wrong magic numbers
  15.  *
  16.  * 13.03.95 crc code from png spec, compiles on memory impaired PCs now,
  17.  *          check for IHDR/IEND chunks
  18.  *
  19.  * 23 Mar 95  glennrp rewrote magic number checking and moved it to
  20.  *             PNG_check_magic(buffer)
  21.  *
  22.  * 27.03.95 AL: fixed CRC code for 64 bit, -t switch, unsigned char vs. char
  23.  *          pointer changes
  24.  *
  25.  * 01.06.95 AL: check for data after IEND chunk
  26.  *
  27.  * 22.08.95 RMF Added prototypes and Defines for different Macintosh and Window's compilers.
  28.  *
  29.  */
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #include <fcntl.h> 
  36.  
  37. #undef MACOS            /* RMF Changes for Macintosh Support... */
  38. #undef WINOS
  39. #undef WIN32OS
  40.  
  41. #if defined(applec) || defined(__MWERKS__) || defined(THINK_C)        // RMF Added "|| defined(__MWERKS__)"
  42.   #define MACOS
  43. #elif defined(_WINDOWS) || defined(MSDOS) || defined(MSC7) || defined(__BORLANDC__) || defined __TURBOC__
  44.   #define WINOS
  45. #elif  defined(__NT__)    || defined(_WIN32) || defined(msvcnt) || defined(mscnt)
  46.   #define WIN32OS
  47. #endif
  48.  
  49. #if defined(MACOS)        
  50. #include <Types.h>
  51. #include <ToolUtils.h>
  52. #define far /* far */
  53. #else
  54. #include <sys/types.h>
  55. #include <sys/stat.h>
  56. #endif
  57.  
  58. /* defined so I can write to a file on gui/windowing platforms */
  59. #define STDERR stderr
  60.  
  61. #define OK      0
  62. #define ERROR   -1
  63. #define WARNING -2
  64.  
  65. void make_crc_table(void);        /* RMF ... Added ProtoTypes missing */
  66. unsigned long update_crc(unsigned long crc, unsigned char *buf, int len);
  67. unsigned long getlong(FILE *fp);
  68. void pngcheck(FILE *fp, char *_fname);    /* RMF End additions */
  69.  
  70. int PNG_check_magic(unsigned char *magic);
  71. int PNG_check_chunk_name(char *chunk_name);
  72.  
  73. #define BS 32000 /* size of read block for CRC calculation */
  74. int verbose; /* ==1 print chunk info */
  75. int printtext; /* ==1 print tEXt chunks */
  76. char *fname;
  77. unsigned char buffer[BS];
  78.  
  79. /* table of crc's of all 8-bit messages */
  80. unsigned long crc_table[256];
  81.  
  82. /* Flag: has the table been computed? Initially false. */
  83. int crc_table_computed = 0;
  84.  
  85.  
  86. /* make the table for a fast crc */
  87. void make_crc_table(void)
  88. {
  89.   unsigned long c;
  90.   int n, k;
  91.  
  92.   for (n = 0; n < 256; n++)
  93.   {
  94.     c = (unsigned long)n;
  95.     for (k = 0; k < 8; k++)
  96.       c = c & 1 ? 0xedb88320L ^ (c >> 1) : c >> 1;
  97.     crc_table[n] = c;
  98.   }
  99.   crc_table_computed = 1;
  100. }
  101.  
  102. /* update a running crc with the bytes buf[0..len-1]--the crc should be
  103.    initialized to all 1's, and the transmitted value is the 1's complement
  104.    of the final running crc. */
  105.  
  106. unsigned long update_crc(unsigned long crc, unsigned char *buf, int len)
  107. {
  108.   unsigned long c = crc;
  109.   unsigned char *p = buf;
  110.   int n = len;
  111.  
  112.   if (!crc_table_computed) {
  113.     make_crc_table();
  114.   }
  115.   if (n > 0) do {
  116.     c = crc_table[(c ^ (*p++)) & 0xff] ^ (c >> 8);
  117.   } while (--n);
  118.   return c;
  119. }
  120.  
  121. /* use these instead of ~crc and -1, since that doesn't work on machines that
  122.    have 64 bit longs */
  123.  
  124. #define CRCCOMPL(c) ((c)^0xffffffff)
  125. #define CRCINIT (CRCCOMPL(0))
  126.  
  127. unsigned long getlong(FILE *fp)
  128. {
  129.   unsigned long res=0;
  130.   int c;
  131.   int i;
  132.  
  133.   for(i=0;i<4;i++) {
  134.     if((c=fgetc(fp))==EOF) {
  135.       printf("%s: EOF while reading 4 bytes value\n", fname);
  136.       return 0;
  137.     }
  138.     res<<=8;
  139.     res|=c&0xff;
  140.   }
  141.   return res;
  142. }
  143.  
  144. void pngcheck(FILE *fp, char *_fname)
  145. {
  146.   long s;
  147.   unsigned char magic[8];
  148.   char chunkid[5];
  149.   int toread;
  150.   int c;
  151.   unsigned long crc, filecrc;
  152.   int first=1;
  153.   int iend_read=0;
  154.  
  155.   fname=_fname; /* make filename available to functions above */
  156.  
  157.   if(fread(magic, 1, 8, fp)!=8) {
  158.     printf("%s: Cannot read PNG header\n", fname);
  159.     return;
  160.   }
  161.  
  162.   if (PNG_check_magic(magic) != 0) return;
  163.  
  164.   while((c=fgetc(fp))!=EOF) {
  165.     ungetc(c, fp);
  166.     if(iend_read) {
  167.       printf("%s: additional data after IEND chunk\n", fname);
  168.       return;
  169.     }
  170.     s=getlong(fp);
  171.     if(fread(chunkid, 1, 4, fp)!=4) {
  172.       printf("%s: EOF while reading chunk type\n", fname);
  173.       return;
  174.     }
  175.  
  176.     chunkid[4]=0;
  177.  
  178.     if (PNG_check_chunk_name(chunkid) != 0) return;
  179.  
  180.     if(verbose) {
  181.       printf("%s: chunk %s at %lx length %lx\n", fname, chunkid, ftell(fp)-4, s);
  182.     }
  183.  
  184.     if(first && strcmp(chunkid,"IHDR")!=0) {
  185.       printf("%s: file doesn't start with a IHDR chunk\n", fname);
  186.     }
  187.     first=0;
  188.  
  189.     crc=update_crc(CRCINIT, (unsigned char *)chunkid, 4);
  190.  
  191.     while(s>0) {
  192.       toread=s;
  193.       if(toread>BS) {
  194.         toread=BS;
  195.       }
  196.       if(fread(buffer, 1, toread, fp)!=toread) {
  197.         printf("%s: EOF while reading chunk data (%s)\n", fname, chunkid);
  198.         return;
  199.       }
  200.       crc=update_crc(crc, buffer, toread);
  201.       s-=toread;
  202.       if(printtext && strcmp(chunkid, "tEXt")==0) {
  203.         if(strlen((char *)buffer)<toread) {
  204.           buffer[strlen((char *)buffer)]=':';
  205.         }
  206.         fwrite(buffer, 1, toread, stdout);
  207.       }
  208.     }
  209.     if(printtext && strcmp(chunkid, "tEXt")==0) {
  210.       printf("\n");
  211.     }
  212.     filecrc=getlong(fp);
  213.     if(filecrc!=CRCCOMPL(crc)) {
  214.       printf("%s: CRC error in chunk %s (actual %08lx, should be %08lx)\n",
  215.               fname, chunkid, CRCCOMPL(crc), filecrc);
  216.       return;
  217.     }
  218.     if(strcmp(chunkid, "IEND")==0) {
  219.       iend_read=1;
  220.     }
  221.   }
  222.   if(!iend_read) {
  223.     printf("%s: file doesn't end with a IEND chunk\n", fname);
  224.     return;
  225.   }
  226.   printf("%s: file appears to be OK\n", fname);
  227. }
  228.  
  229. int main(int argc, char *argv[])
  230. {
  231.   FILE *fp;
  232.   int i;
  233.  
  234.     fprintf(STDERR, "Checking PNG Files…\n");
  235.     
  236.   if(argc>1 && strcmp(argv[1],"-v")==0) {
  237.     verbose=1;
  238.     argc--;
  239.     argv++;
  240.   } else
  241.   if(argc>1 && strcmp(argv[1],"-t")==0) {
  242.     printtext=1;
  243.     argc--;
  244.     argv++;
  245.   }
  246.  
  247.   if(argc==1) {
  248. #if defined(MACOS)
  249.     printf("No PNG File\n");
  250.     fprintf(STDERR, "NoPGN File\n");
  251.     SysBeep(0);
  252. #else  
  253.     pngcheck(stdin, "stdin");
  254. #endif
  255.   } else {
  256.     for(i=1;i<argc;i++) {
  257.       if((fp=fopen(argv[i],"rb"))==NULL) {
  258.         perror(argv[i]);
  259.       } else {
  260.         pngcheck(fp, argv[i]);
  261.         fclose(fp);
  262.       }
  263.     }
  264.   }
  265.  
  266.   return 0;
  267. }
  268.  
  269. /*  PNG_subs
  270.  *
  271.  *  Utility routines for PNG encoders and decoders
  272.  *  by Glenn Randers-Pehrson
  273.  *
  274.  */
  275.  
  276.  
  277. /* (int)PNG_check_magic ((unsigned char*) magic)
  278.  *
  279.  * check the magic numbers in 8-byte buffer at the beginning of
  280.  * a PNG file.
  281.  *
  282.  * by Alexander Lehmann and Glenn Randers-Pehrson
  283.  *
  284.  * This is free software; you can redistribute it and/or modify it
  285.  * without any restrictions.
  286.  *
  287.  */
  288.  
  289. int PNG_check_magic(unsigned char *magic)
  290. {
  291.     if (strncmp((char *)&magic[1],"PNG",3) != 0) {
  292.              fprintf(stderr, "not a PNG file\n");
  293.              return(ERROR);
  294.             }
  295.  
  296.     if (magic[0] != 0x89 ||
  297.          strncmp((char *)&magic[4],"\015\012\032\012",4) != 0) {
  298.          fprintf(stderr, "PNG file is CORRUPTED.\n");
  299.  
  300.          /* this coding taken from Alexander Lehmanns checkpng code   */
  301.  
  302.         if(strncmp((char *)&magic[4],"\n\032",2) == 0) fprintf
  303.              (stderr," It seems to have suffered DOS->unix conversion\n");
  304.         else
  305.         if(strncmp((char *)&magic[4],"\r\032",2) == 0) fprintf
  306.              (stderr," It seems to have suffered DOS->Mac conversion\n");
  307.         else
  308.         if(strncmp((char *)&magic[4],"\r\r\032",3) == 0) fprintf
  309.              (stderr," It seems to have suffered unix->Mac conversion\n");
  310.         else
  311.         if(strncmp((char *)&magic[4],"\n\n\032",3) == 0) fprintf
  312.              (stderr," It seems to have suffered Mac-unix conversion\n");
  313.         else
  314.         if(strncmp((char *)&magic[4],"\r\n\032\r",4) == 0) fprintf
  315.              (stderr," It seems to have suffered unix->DOS conversion\n");
  316.         else
  317.         if(strncmp((char *)&magic[4],"\r\r\n\032",4) == 0) fprintf
  318.              (stderr," It seems to have suffered unix->DOS conversion\n");
  319.         else
  320.         if(strncmp((char *)&magic[4],"\r\n\032\n",4) != 0) fprintf
  321.              (stderr," It seems to have suffered EOL conversion\n");
  322.  
  323.         if(magic[0]==9) fprintf
  324.              (stderr," It was probably transmitted through a 7bit channel\n");
  325.         else
  326.         if(magic[0]!=0x89) fprintf
  327.              (stderr,"  It was probably transmitted in text mode\n");
  328.         /*  end of Alexander Lehmann's code  */
  329.         return(ERROR);
  330.         }
  331.     return (OK);
  332. }
  333.  
  334. /* (int)PNG_check_magic ((char*) magic)
  335.  *
  336.  * from Alex Lehmann
  337.  *
  338.  */
  339.  
  340. int PNG_check_chunk_name(char *chunk_name)
  341. {
  342.      if(!isalpha(chunk_name[0]) || !isalpha(chunk_name[1]) ||
  343.         !isalpha(chunk_name[2]) || !isalpha(chunk_name[3])) {
  344.          printf("chunk name %02x %02x %02x %02x doesn't comply to naming rules\n",
  345.          chunk_name[0],chunk_name[1],chunk_name[2],chunk_name[3]);
  346.          return (ERROR);
  347.          }
  348.      else return (OK);
  349. }
  350.